package com.atlin.nrpc.core.proxy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.atlin.nrpc.core.RpcApplication;
import com.atlin.nrpc.core.config.RpcConfig;
import com.atlin.nrpc.core.constant.RpcConstant;
import com.atlin.nrpc.core.model.RpcRequest;
import com.atlin.nrpc.core.model.RpcResponse;
import com.atlin.nrpc.core.model.ServiceMetaInfo;
import com.atlin.nrpc.core.registry.Registry;
import com.atlin.nrpc.core.registry.RegistryFactory;
import com.atlin.nrpc.core.serializer.Serializer;
import com.atlin.nrpc.core.serializer.SerializerFactory;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 服务代理
 */
@Slf4j
public class ServiceProxy implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//        JdkSerializer serializer = new JdkSerializer();
        // 使用动态配置文件指定的序列化器
        final Serializer serializer = SerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());
        log.info("use serializer = {}", serializer.getClass().getName());
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();

        try {
            byte[] bodyBytes = serializer.serialize(rpcRequest);
            byte[] result;
            // 发送请求
            // todo 使用注册中心实现 解除此处硬编码问题
            String serverHost = RpcApplication.getRpcConfig().getServerHost();
            int serverPort = RpcApplication.getRpcConfig().getServerPort();
            RpcConfig rpcConfig = RpcApplication.getRpcConfig();
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());

            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(serviceName);
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);

            List<ServiceMetaInfo> serviceMetaInfos = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfos)) {
//                System.out.println("暂无服务地址");
                throw new RuntimeException("暂无服务地址");
            }

            // todo 暂时先用第一个服务
            ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfos.get(0);


            // String.format("http://%s:%s/rpc", serverHost, serverPort)
            try (HttpResponse httpResponse = HttpRequest.post(selectedServiceMetaInfo.getServiceAddress())
                    .body(bodyBytes)
                    .execute()) {
                result = httpResponse.bodyBytes();
            }
            RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
            return rpcResponse.getData();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
